package com.example.system.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.system.domain.curriculumSchedule.CurriculumSchedule;
import com.example.system.domain.curriculumSchedule.dto.CurriculumScheduleQueryDTO;
import com.example.system.domain.curriculumSchedule.dto.CurriculumScheduleSaveDTO;
import com.example.system.domain.curriculumSchedule.dto.CourseSchedule;
import com.example.system.mapper.CurriculumScheduleMapper;
import com.example.system.service.ICurriculumScheduleService;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
@Transactional(readOnly = true)
public class CurriculumScheduleServiceImpl extends ServiceImpl<CurriculumScheduleMapper, CurriculumSchedule> implements ICurriculumScheduleService {
    @Autowired
    private CurriculumScheduleMapper curriculumScheduleMapper;
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean update(CurriculumScheduleSaveDTO curriculumScheduleSaveDTO) {
        conflictJudgment(curriculumScheduleSaveDTO);

        String startDate = curriculumScheduleSaveDTO.getStartDate();
        String endDate = curriculumScheduleSaveDTO.getEndDate();

        LambdaQueryWrapper<CurriculumSchedule> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper
                .eq(CurriculumSchedule::getClassroomId,curriculumScheduleSaveDTO.getClassroomId())
                .ge(CurriculumSchedule::getDate, startDate) // 大于等于开始日期
                .le(CurriculumSchedule::getDate, endDate);
        curriculumScheduleMapper.delete(queryWrapper);

        Long classroomId = curriculumScheduleSaveDTO.getClassroomId();
        String classroomName = curriculumScheduleSaveDTO.getClassroomName();
        Map<Integer, List<Object>> courseData = curriculumScheduleSaveDTO.getCourseData();
        if(courseData == null || courseData.size() == 0){
            return true;
        }
        List<CurriculumSchedule> curriculumScheduleList = new ArrayList<>();
        for (Map.Entry<Integer, List<Object>> entry : courseData.entrySet()) {
            for (int i = 0; i < entry.getValue().size()-1; i++) {
                if(entry.getValue().get(i)!=null){
                    CourseSchedule courseSchedule = convertToCourseSchedule(entry.getValue().get(i));
                    CurriculumSchedule curriculumSchedule = new CurriculumSchedule();
                    curriculumSchedule.setClassroomId(classroomId);
                    curriculumSchedule.setClassroomName(classroomName);
                    curriculumSchedule.setCourseId(courseSchedule.getCourseId());
                    curriculumSchedule.setCourseName(courseSchedule.getCourseName());
                    curriculumSchedule.setTeacherId(courseSchedule.getTeacherId());
                    curriculumSchedule.setTeacherName(courseSchedule.getTeacherName());
                    curriculumSchedule.setTime(i);
                    curriculumSchedule.setDate(entry.getValue().get(3).toString());
                    curriculumScheduleList.add(curriculumSchedule);
                }
            }
        }
        // 批量插入
        return saveBatch(curriculumScheduleList);
    }

    private void conflictJudgment(CurriculumScheduleSaveDTO curriculumScheduleSaveDTO) {
        Map<Integer, List<Object>> courseData = curriculumScheduleSaveDTO.getCourseData();
        for (Map.Entry<Integer, List<Object>> entry : courseData.entrySet()) {
            for (int i = 0; i < entry.getValue().size()-1; i++) {
                if(entry.getValue().get(i)!=null){
                    CourseSchedule courseSchedule = convertToCourseSchedule(entry.getValue().get(i));
                    LambdaQueryWrapper<CurriculumSchedule> queryWrapper = new LambdaQueryWrapper<>();
                    queryWrapper
                            .ne(CurriculumSchedule::getClassroomId,curriculumScheduleSaveDTO.getClassroomId())
                            .eq(CurriculumSchedule::getTeacherId, courseSchedule.getTeacherId())
                            .eq(CurriculumSchedule::getDate, entry.getValue().get(3).toString())
                            .eq(CurriculumSchedule::getTime,i);
                    List<CurriculumSchedule> curriculumSchedules = curriculumScheduleMapper.selectList(queryWrapper);
                    if(CollectionUtil.isNotEmpty(curriculumSchedules)){
                        CurriculumSchedule curriculumSchedule = curriculumSchedules.get(0);
                        String teacherName = curriculumSchedule.getTeacherName();
                        String classroomName = curriculumSchedule.getClassroomName();
                        String date = curriculumSchedule.getDate();
                        Integer time = curriculumSchedule.getTime(); // 0 上午，1 下午， 2 晚上
                        String timeSlot = "";
                        switch (time) {
                            case 0:
                                timeSlot = "上午(9:00-12:00)";
                                break;
                            case 1:
                                timeSlot = "下午(14:00-17:00)";
                                break;
                            case 2:
                                timeSlot = "晚上(19:00-22:00)";
                                break;
                        }
                        String errorMessage = String.format("教师 %s 在%s班 %s 的 %s 已经被安排了课程，请重新安排课程",
                                teacherName,
                                classroomName,
                                date,
                                timeSlot);
                        throw new RuntimeException(errorMessage);
                    }
                }
            }
        }
    }

    private CourseSchedule convertToCourseSchedule(Object obj) {
        // 使用 Jackson 或 Gson 将 Object 转换为 CourseSchedule
        ObjectMapper mapper = new ObjectMapper();
        return mapper.convertValue(obj, CourseSchedule.class);
    }
    @Override
    public Map<Integer, List<Object>> get(CurriculumScheduleQueryDTO curriculumScheduleQueryDTO) {
        Map<Integer, List<Object>> result = new HashMap<>();
        for (int i = 0; i < 7; i++) {
            List<Object> daySchedule = new ArrayList<>();
            daySchedule.add(null);  // 上午
            daySchedule.add(null);  // 下午
            daySchedule.add(null);  // 晚上
            daySchedule.add(getDateByDay(curriculumScheduleQueryDTO.getStartDate(), i));  // 日期
            result.put(i, daySchedule);
        }

        Long classroomId = curriculumScheduleQueryDTO.getClassroomId();
        String startDate = curriculumScheduleQueryDTO.getStartDate();
        String endDate = curriculumScheduleQueryDTO.getEndDate();

        // 构建查询条件
        LambdaQueryWrapper<CurriculumSchedule> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper
                .select(CurriculumSchedule::getCourseId,
                        CurriculumSchedule::getCourseName,
                        CurriculumSchedule::getTeacherId,
                        CurriculumSchedule::getTeacherName,
                        CurriculumSchedule::getDate,
                        CurriculumSchedule::getTime)
                .eq(CurriculumSchedule::getClassroomId, classroomId)
                .ge(CurriculumSchedule::getDate, startDate)
                .le(CurriculumSchedule::getDate, endDate)
                .orderByAsc(CurriculumSchedule::getDate)
                .orderByAsc(CurriculumSchedule::getTime);
        List<CurriculumSchedule> curriculumSchedules = curriculumScheduleMapper.selectList(queryWrapper);
        // 处理查询结果
        for (CurriculumSchedule schedule : curriculumSchedules) {
            // 计算日期差（星期几）
            int dayIndex = calculateDateDifference(startDate, schedule.getDate());
            // 创建课程对象
            Map<String, String> course = new HashMap<>();
            course.put("courseId", schedule.getCourseId().toString());
            course.put("courseName", schedule.getCourseName());
            course.put("teacherId", schedule.getTeacherId().toString());
            course.put("teacherName", schedule.getTeacherName());

            // 设置到对应的时间段
            result.get(dayIndex).set(schedule.getTime(), course);
        }

        return result;
    }

    /**
     * 根据开始日期和星期几获取具体日期
     * @param startDate 开始日期
     * @param day 星期几（0-6）
     * @return 具体日期
     */
    private String getDateByDay(String startDate, int day) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        LocalDate date = LocalDate.parse(startDate, formatter);
        return date.plusDays(day).format(formatter);
    }

    /**
     * 计算两个日期之间的天数差
     * @param dateStr1 第一个日期字符串
     * @param dateStr2 第二个日期字符串
     * @return 天数差
     */
    private int calculateDateDifference(String dateStr1, String dateStr2) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        LocalDate date1 = LocalDate.parse(dateStr1, formatter);
        LocalDate date2 = LocalDate.parse(dateStr2, formatter);
        return (int) ChronoUnit.DAYS.between(date1, date2);
    }
}
